package edu.suda.cxtz.service.impl;

import edu.suda.cxtz.entity.User;
import edu.suda.cxtz.modules.security.service.UserCacheManager;
import edu.suda.cxtz.repository.UserRepository;
import edu.suda.cxtz.entity.dto.UserDto;
import edu.suda.cxtz.entity.dto.UserLoginDto;
import edu.suda.cxtz.entity.dto.UserQueryCriteria;
import edu.suda.cxtz.service.UserService;
import edu.suda.cxtz.utils.*;
import edu.suda.cxtz.modules.exception.EntityExistException;
import edu.suda.cxtz.modules.exception.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Pageable;


import java.util.*;

@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "user")
public class UserServiceImpl implements UserService {

    private final UserRepository userRepository;
    private final UserCacheManager userCacheManager;
    private final DtoEntityUtil mapper;
    private final RedisUtils redisUtils;

    @Override
    public PageResult<UserDto> queryAll(UserQueryCriteria criteria, Pageable pageable) throws Exception{
        Page<User> page = userRepository.findAll((root, query, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);
        List<UserDto> pageResult = mapper.trans(page, UserDto.class);
        return PageUtil.toPage(pageResult, page.getTotalElements());
    }

    @Override
    public List<UserDto> queryAll() {
        return mapper.trans(userRepository.findAll(), UserDto.class);
    }

    @Override
    @Cacheable(key = "'id:' + #p0")
    @Transactional(rollbackFor = Exception.class)
    public UserDto findById(long id) {
        User user = userRepository.findById(id).orElseGet(User::new);
        ValidationUtil.isNull(user.getId(), "User", "id", id);
        return mapper.trans(user, UserDto.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(User resources) {
        if (userRepository.findByUsername(resources.getUsername()) != null) {
            throw new EntityExistException(User.class, "username", resources.getUsername());
        }
        if (userRepository.findByEmail(resources.getEmail()) != null) {
            throw new EntityExistException(User.class, "email", resources.getEmail());
        }
        if (userRepository.findByPhone(resources.getPhone()) != null) {
            throw new EntityExistException(User.class, "phone", resources.getPhone());
        }
        userRepository.save(resources);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(User resources) throws Exception {
        User user = userRepository.findById(resources.getId()).orElseGet(User::new);
        ValidationUtil.isNull(user.getId(), "User", "id", resources.getId());
        User user1 = userRepository.findByUsername(resources.getUsername());
        User user2 = userRepository.findByEmail(resources.getEmail());
        User user3 = userRepository.findByPhone(resources.getPhone());
        if (user1 != null && !user.getId().equals(user1.getId())) {
            throw new EntityExistException(User.class, "username", resources.getUsername());
        }
        if (user2 != null && !user.getId().equals(user2.getId())) {
            throw new EntityExistException(User.class, "email", resources.getEmail());
        }
        if (user3 != null && !user.getId().equals(user3.getId())) {
            throw new EntityExistException(User.class, "phone", resources.getPhone());
        }
        // 如果用户被禁用，则清除用户登录信息
/*
        if(!resources.getEnabled()){
            onlineUserService.kickOutForUsername(resources.getUsername());
        }
*/
        user.setUsername(resources.getUsername());
        user.setEmail(resources.getEmail());
        user.setEnabled(resources.getEnabled());
        user.setRoles(resources.getRoles());
        user.setDept(resources.getDept());
        user.setJobs(resources.getJobs());
        user.setPhone(resources.getPhone());
        user.setNickName(resources.getNickName());
        user.setGender(resources.getGender());
        userRepository.save(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCenter(User resources) {
        User user = userRepository.findById(resources.getId()).orElseGet(User::new);
        User user1 = userRepository.findByPhone(resources.getPhone());
        if (user1 != null && !user.getId().equals(user1.getId())) {
            throw new EntityExistException(User.class, "phone", resources.getPhone());
        }
        user.setNickName(resources.getNickName());
        user.setPhone(resources.getPhone());
        user.setGender(resources.getGender());
        userRepository.save(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Set<Long> ids) {
        for (Long id : ids) {
            UserDto user = findById(id);
             delCaches(user.getId(), user.getUsername());
        }
        userRepository.deleteAllByIdIn(ids);
    }

    @Override
    public UserDto findByName(String userName) {
        User user = userRepository.findByUsername(userName);
        if (user == null) {
            throw new EntityNotFoundException(User.class, "name", userName);
        } else {
            return mapper.trans(user, UserDto.class);
        }
    }

    @Override
    public UserLoginDto getLoginData(String userName) {
        User user = userRepository.findByUsername(userName);
        if (user == null) {
            throw new EntityNotFoundException(User.class, "name", userName);
        } else {
            return mapper.trans(user, UserLoginDto.class);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePass(String username, String pass) {
        userRepository.updatePass(username, pass, new Date());
         flushCache(username);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetPwd(Set<Long> ids, String pwd) {
        userRepository.resetPwd(ids, pwd);
    }

    /**
     * 更新用户头像。
     *
     * @param multipartFile 上传的文件，预期为用户的新头像。
     * @return 包含新头像名称的映射。
     * @throws BadRequestException 如果上传的文件格式不正确。
     */
    /*
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, String> updateAvatar(MultipartFile multipartFile) {
        // 检查上传文件的大小是否符合规定
        // 文件大小验证
        FileUtil.checkSize(properties.getAvatarMaxSize(), multipartFile.getSize());

        // 验证上传文件的类型是否为允许的图像格式
        // 验证文件上传的格式
        String image = "gif jpg png jpeg";
        String fileType = FileUtil.getExtensionName(multipartFile.getOriginalFilename());
        if (fileType != null && !image.contains(fileType)) {
            throw new BadRequestException("文件格式错误！, 仅支持 " + image + " 格式");
        }

        // 根据当前登录用户的用户名获取用户对象
        User user = userRepository.findByUsername(SecurityUtils.getCurrentUsername());
        String oldPath = user.getAvatarPath();

        // 上传新头像文件并获取新文件路径及名称
        File file = FileUtil.upload(multipartFile, properties.getPath().getAvatar());

        user.setAvatarPath(file.getPath());
        user.setAvatarName(file.getName());

        // 保存更新后的用户信息
        userRepository.save(user);

        // 如果存在旧头像路径，则删除旧头像文件
        if (StringUtils.isNotBlank(oldPath)) {
            FileUtil.del(oldPath);
        }

        // 刷新用户头像缓存
        @NotBlank String username = user.getUsername();
        flushCache(username);

        // 返回包含新头像名称的映射
        return new HashMap<String, String>(1) {{
            put("avatar", file.getName());
        }};
    }
*/


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateEmail(String username, String email) {
        userRepository.updateEmail(username, email);
         flushCache(username);
    }
    /**
     * 清理缓存
     *
     * @param id /
     */
    public void delCaches(Long id, String username) {
        redisUtils.del(CacheKey.USER_ID + id);
        flushCache(username);
    }
    /*
     * 清理 登陆时 用户缓存信息
     *
     * @param username /
     */
    private void flushCache(String username) {
        userCacheManager.cleanUserCache(username);
    }
}

